#!/usr/bin/env python3
"""
MCP工具生成器主程序
负责从Excel生成MCP函数和管理函数注册表
"""

import os
import sys
import shutil
from pathlib import Path
from fastapi import FastAPI, File, UploadFile, HTTPException
from fastapi.responses import JSONResponse, RedirectResponse
from pydantic import BaseModel
from fastapi.staticfiles import StaticFiles
from starlette.middleware.cors import CORSMiddleware

# 添加项目根目录到路径
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))

from mcp_generator.excel_parser import parse_excel_and_merge_logic
from mcp_generator.function_code_generator import FunctionCodeGenerator
from mcp_generator.function_manager import FunctionManager
from shared.config.llm_config import get_mcp_generator_config

# FastAPI应用
app = FastAPI(
    title="MCP Function Generator",
    description="MCP函数生成和管理服务",
    version="2.0.0"
)

@app.get("/health")
async def health_check():
    """健康检查端点"""
    return {"status": "healthy", "service": "MCP Function Generator", "version": "2.0.0"}

# CORS配置
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 路径配置
GENERATOR_DIR = Path(__file__).parent
# 使用共享目录 - 计算到项目根目录
workspace_root = Path(__file__).parent.parent.parent.parent  # 到达 xjc_MCP_GEN 根目录
SHARED_DIR = workspace_root / "shared"
FUNCTIONS_DIR = SHARED_DIR / "generated" / "functions"
REGISTRY_PATH = SHARED_DIR / "generated" / "function_registry.json"
KNOWLEDGE_BASE_DIR = SHARED_DIR / "knowledge_base"

# 确保目录存在
FUNCTIONS_DIR.mkdir(parents=True, exist_ok=True)
KNOWLEDGE_BASE_DIR.mkdir(parents=True, exist_ok=True)

# 初始化组件
function_code_generator = FunctionCodeGenerator(get_mcp_generator_config())
function_manager = FunctionManager(str(REGISTRY_PATH), str(FUNCTIONS_DIR))


@app.post("/upload-and-generate")
async def upload_and_generate(file: UploadFile = File(...)):
    """上传Excel并生成函数"""
    temp_file_path = GENERATOR_DIR / f"temp_{file.filename}"
    try:
        # 保存临时文件
        with open(temp_file_path, "wb") as buffer:
            shutil.copyfileobj(file.file, buffer)

        # 解析Excel
        print(f"Parsing Excel file: {temp_file_path}")
        try:
            logics = parse_excel_and_merge_logic(str(temp_file_path))
            if not logics:
                print(f"ERROR: Excel parsing failed or no logic found in file: {temp_file_path}")
                raise HTTPException(status_code=400, detail="Failed to parse Excel or no logic found.")
            print(f"Successfully parsed Excel, found {len(logics)} indicators")
        except Exception as parse_error:
            print(f"ERROR: Exception during Excel parsing: {str(parse_error)}")
            print(f"ERROR: Parse error type: {type(parse_error).__name__}")
            import traceback
            print(f"ERROR: Parse traceback: {traceback.format_exc()}")
            raise HTTPException(status_code=400, detail=f"Excel解析失败: {str(parse_error)}")

        # 生成函数
        new_functions_count = 0
        updated_functions_count = 0
        skipped_functions_count = 0
        failed_functions = []
        
        for indicator, logic_details in logics.items():
            print(f"Processing indicator: {indicator}")
            print(f"  Logic details keys: {list(logic_details.keys())}")
            
            # 提取时间戳信息
            excel_created_at = logic_details.get('created_at')
            excel_updated_at = logic_details.get('updated_at')
            print(f"  Excel timestamps - Created: {excel_created_at}, Updated: {excel_updated_at}")
            
            # 检查是否需要生成代码 - 只基于时间戳判断
            existing_function = function_manager.functions.get(indicator)
            should_generate = True  # 默认生成
            
            if existing_function:
                # 如果函数已存在，检查时间戳是否有变化
                existing_created = existing_function.get('excel_created_at')
                existing_updated = existing_function.get('excel_updated_at')
                
                print(f"  Existing timestamps - Created: {existing_created}, Updated: {existing_updated}")
                
                # 只有当时间戳完全相同且都不为None时才跳过
                timestamps_match = (
                    excel_created_at == existing_created and 
                    excel_updated_at == existing_updated and
                    excel_created_at is not None and 
                    excel_updated_at is not None and
                    existing_created is not None and 
                    existing_updated is not None
                )
                
                if timestamps_match:
                    should_generate = False
                    print(f"Skipped function (no timestamp changes): {indicator}")
                else:
                    print(f"Will generate/update function (timestamp changes detected): {indicator}")
                    if excel_created_at != existing_created:
                        print(f"  Created timestamp changed: {existing_created} -> {excel_created_at}")
                    if excel_updated_at != existing_updated:
                        print(f"  Updated timestamp changed: {existing_updated} -> {excel_updated_at}")
            
            if not should_generate:
                skipped_functions_count += 1
                continue
            
            print(f"Generating function code for: {indicator}")
            
            # 生成代码时排除时间戳字段
            logic_for_generation = {k: v for k, v in logic_details.items() 
                                  if k not in ['created_at', 'updated_at']}
            
            print(f"Generating function code for: {indicator}")
            try:
                generated_code = function_code_generator.generate_function_code(indicator, logic_for_generation)
                
                if generated_code:
                    print(f"Successfully generated code for: {indicator}")
                    # 注册函数
                    try:
                        operation_type = function_manager.register_function(
                            indicator,
                            generated_code,
                            file.filename,
                            excel_created_at,
                            excel_updated_at
                        )
                        
                        if operation_type == 'new':
                            new_functions_count += 1
                            print(f"Added new function: {indicator}")
                        elif operation_type == 'updated':
                            updated_functions_count += 1
                            print(f"Updated existing function: {indicator}")
                        else:
                            skipped_functions_count += 1
                    except Exception as register_error:
                        print(f"ERROR: Failed to register function '{indicator}': {str(register_error)}")
                        print(f"ERROR: Register error type: {type(register_error).__name__}")
                        import traceback
                        print(f"ERROR: Register traceback: {traceback.format_exc()}")
                        failed_functions.append(indicator)
                else:
                    failed_functions.append(indicator)
                    print(f"ERROR: Failed to generate function code for '{indicator}' - generated_code is empty")
                    
            except Exception as generation_error:
                print(f"ERROR: Exception during code generation for '{indicator}': {str(generation_error)}")
                print(f"ERROR: Generation error type: {type(generation_error).__name__}")
                import traceback
                print(f"ERROR: Generation traceback: {traceback.format_exc()}")
                failed_functions.append(indicator)

        # 更新知识库
        kb_update_success = True
        if new_functions_count > 0 or updated_functions_count > 0:
            try:
                await update_knowledge_base()
                # 通知MCP Server重新加载函数注册表
                notify_mcp_server_reload()
            except Exception as e:
                kb_update_success = False
                print(f"❌ Knowledge base update failed: {e}")
                
                # 如果知识库更新失败，回滚所有新增/更新的函数
                print("🔄 Rolling back functions due to knowledge base update failure...")
                rollback_functions = []
                
                # 收集需要回滚的函数名
                for indicator, logic_details in logics.items():
                    existing_function = function_manager.get_function_info(indicator)
                    if existing_function:
                        # 检查是否是本次操作新增或更新的
                        excel_created_at = logic_details.get('created_at')
                        excel_updated_at = logic_details.get('updated_at')
                        if (excel_created_at and excel_updated_at and 
                            (existing_function.get('created_at') == excel_created_at or 
                             existing_function.get('updated_at') == excel_updated_at)):
                            rollback_functions.append(indicator)
                
                # 执行回滚
                for func_name in rollback_functions:
                    try:
                        function_manager.remove_function(func_name)
                        print(f"🔄 Rolled back function: {func_name}")
                    except Exception as rollback_error:
                        print(f"❌ Failed to rollback function {func_name}: {rollback_error}")
                
                # 重置计数器
                new_functions_count = 0
                updated_functions_count = 0
                failed_functions.extend(rollback_functions)

        # 返回结果
        if not kb_update_success:
            message = f"❌ Function generation failed due to knowledge base update error. "
            message += f"Rolled back {len(failed_functions)} functions."
            return JSONResponse(content={"message": message, "success": False}, status_code=500)
        
        message = f"✅ Successfully processed {len(logics)} indicators. "
        message += f"New: {new_functions_count}, Updated: {updated_functions_count}, Skipped: {skipped_functions_count}."
        if failed_functions:
            message += f" Failed functions: {', '.join(failed_functions)}"
            
        return JSONResponse(content={"message": message, "success": True}, status_code=200)

    except Exception as e:
        print(f"ERROR: Unexpected exception in upload_and_generate: {str(e)}")
        print(f"ERROR: Exception type: {type(e).__name__}")
        import traceback
        print(f"ERROR: Full traceback: {traceback.format_exc()}")
        raise HTTPException(status_code=500, detail=f"上传生成失败: {str(e)}")
    finally:
        # 清理临时文件
        if temp_file_path.exists():
            temp_file_path.unlink()


def notify_mcp_server_reload():
    """通知MCP Server重新加载函数注册表"""
    try:
        import requests
        # 首先尝试通知MCP Server管理服务（端口8011） - 这是正确的服务
        response = requests.post("http://localhost:8011/force-reload-functions", timeout=15)
        if response.status_code == 200:
            result = response.json()
            print(f"✅ MCP Server管理服务已重新加载函数: {result.get('message', '')}")
        else:
            print(f"⚠️ 通知MCP Server管理服务重新加载失败，状态码: {response.status_code}")
            print(f"⚠️ 可能的原因：MCP Server管理服务未启动，请运行 'python -m services.mcp-server.mcp_server.main'")
    except Exception as e:
        print(f"⚠️ 通知MCP Server管理服务重新加载异常: {e}")
        print(f"⚠️ 请确保MCP Server管理服务在端口8011上运行")
        # 备用：如果8011端口失败，尝试8000端口（生成的MCP Server脚本）
        try:
            response = requests.post("http://localhost:8000/force-reload-functions", timeout=15)
            if response.status_code == 200:
                result = response.json()
                print(f"✅ 备用：生成的MCP Server脚本已重新加载函数: {result.get('message', '')}")
            else:
                print(f"⚠️ 备用：生成的MCP Server脚本也没有响应")
        except Exception as e2:
            print(f"⚠️ 两个MCP Server端口都无法访问，请检查服务状态")


@app.get("/functions")
async def get_functions():
    """获取所有函数信息"""
    # 转换为前端期望的格式
    function_list = []
    for name, info in function_manager.functions.items():
        function_list.append({
            "name": name,
            "description": info.get("description", ""),
            "excel_file": info.get("excel_file", ""),
            "created_at": info.get("created_at", ""),
            "updated_at": info.get("updated_at", "")
        })
    
    return JSONResponse(content={
        "functions": function_list,
        "count": len(function_list)
    }, status_code=200)


@app.get("/function-list")
async def get_function_list():
    """获取函数列表（结构化格式）"""
    function_list = function_manager.get_function_list()
    return JSONResponse(content={
        "functions": function_list,
        "count": len(function_list)
    }, status_code=200)


@app.get("/function-list-text")
async def get_function_list_text():
    """获取函数列表（文本格式，用于RAG）"""
    function_list_text = function_manager.get_function_list_text()
    return JSONResponse(content={
        "function_list_text": function_list_text
    }, status_code=200)


class RemoveFunctionRequest(BaseModel):
    function_name: str

@app.delete("/functions")
async def remove_function(request: RemoveFunctionRequest):
    """删除单个函数"""
    function_name = request.function_name
    try:
        # 检查函数是否存在
        function_info = function_manager.get_function_info(function_name)
        if not function_info:
            raise HTTPException(status_code=404, detail=f"函数 '{function_name}' 不存在")
        
        # 删除函数
        success = function_manager.remove_function(function_name)
        if not success:
            raise HTTPException(status_code=500, detail=f"删除函数 '{function_name}' 失败")
        
        print(f"✅ MCP Generator中已删除函数: {function_name}")
        return {"message": f"函数 '{function_name}' 已从MCP Generator中删除"}
        
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"删除函数失败: {str(e)}")


@app.delete("/clear-functions")
async def clear_all_functions():
    """清空所有函数"""
    try:
        function_manager.clear_all()
        print("✅ MCP Generator中已清空所有函数")
        return {"message": "所有函数已从MCP Generator中清空"}
        
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"清空函数失败: {str(e)}")




@app.post("/refresh-knowledge-base")
async def refresh_knowledge_base():
    """全量刷新知识库"""
    try:
        await update_knowledge_base()
        return {"message": "Knowledge base refreshed successfully"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


async def update_knowledge_base():
    """更新知识库并刷新RAG向量嵌入"""
    # 清理旧的知识库文件
    knowledge_base_files = list(KNOWLEDGE_BASE_DIR.glob("*.txt"))
    for file in knowledge_base_files:
        file.unlink()
    
    # 生成新的知识库
    function_list_text = function_manager.get_function_list_text()
    function_list = function_manager.get_function_list()
    
    # 保存文本格式知识库
    kb_text_file = KNOWLEDGE_BASE_DIR / "function_knowledge_base.txt"
    with open(kb_text_file, 'w', encoding='utf-8') as f:
        f.write(function_list_text)
    
    # 保存JSON格式知识库
    import json
    kb_json_file = KNOWLEDGE_BASE_DIR / "function_knowledge_base.json"
    with open(kb_json_file, 'w', encoding='utf-8') as f:
        json.dump({
            "functions": function_list,
            "count": len(function_list),
            "updated_at": function_manager.get_function_list()[0].get('updated_at') if function_list else None
        }, f, ensure_ascii=False, indent=2)
    
    print(f"✅ Knowledge base updated: {len(function_list)} functions")
    
    # 触发RAG知识库增量更新（而不是全量刷新）
    try:
        import requests
        # 调用增量更新接口，而不是全量刷新
        response = requests.post("http://localhost:8080/api/rag/update", timeout=30)
        if response.status_code == 200:
            print("✅ RAG knowledge base updated incrementally")
        else:
            error_msg = f"RAG knowledge base update failed with status {response.status_code}"
            try:
                error_detail = response.json()
                error_msg += f": {error_detail.get('detail', 'Unknown error')}"
            except:
                pass
            print(f"❌ {error_msg}")
            raise Exception(error_msg)
    except requests.exceptions.RequestException as e:
        error_msg = f"Failed to connect to RAG service: {e}"
        print(f"❌ {error_msg}")
        raise Exception(error_msg)
    except Exception as e:
        if "RAG knowledge base update failed" in str(e):
            raise  # 重新抛出我们自己的错误
        error_msg = f"Unexpected error updating RAG knowledge base: {e}"
        print(f"❌ {error_msg}")
        raise Exception(error_msg)



if __name__ == "__main__":
    import uvicorn
    print("🚀 Starting MCP Function Generator...")
    print(f"Functions directory: {FUNCTIONS_DIR}")
    print(f"Registry path: {REGISTRY_PATH}")
    print(f"Knowledge base directory: {KNOWLEDGE_BASE_DIR}")
    
    uvicorn.run(app, host="0.0.0.0", port=8010)
